import hashlib
import binascii
import os

from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC


# 11、哈希加密类
class Hash_Encryption_Management:
    def __init__(self):
        """
        哈希加密类

        """
        self.origin_password = None
        self.encrypt_password = None
        pass

    def sha_256_encrypt(self, password):
        """
        使用sha_256方法加密 \n

        :param password:传入密码 \n
        :return:返回加密后的文本 \n
        """
        hashed_password = hashlib.sha256(password.encode()).hexdigest()
        self.origin_password = password
        self.encrypt_password = hashed_password
        return hashed_password

    def sha_1_encrypt(self, password):
        """
        使用sha_1方法加密 \n

        :param password:传入密码 \n
        :return:返回加密后的文本 \n
        """
        hashed_password = hashlib.sha1(password.encode()).hexdigest()
        self.origin_password = password
        self.encrypt_password = hashed_password
        return hashed_password

    def md5_encrypt(self, password):
        """
        使用md5方法加密 \n

        :param password:传入密码 \n
        :return:返回加密后的文本 \n
        """
        hashed_password = hashlib.md5(password.encode()).hexdigest()
        self.origin_password = password
        self.encrypt_password = hashed_password
        return hashed_password

    def sha_224_encrypt(self, password):
        """
        使用sha_224方法加密 \n

        :param password:传入密码 \n
        :return:返回加密后的文本 \n
        """
        hashed_password = hashlib.sha224(password.encode()).hexdigest()
        self.origin_password = password
        self.encrypt_password = hashed_password
        return hashed_password

    def sha_512_encrypt(self, password):
        """
        使用sha_512方法加密 \n

        :param password:传入密码 \n
        :return:返回加密后的文本 \n
        """
        hashed_password = hashlib.sha512(password.encode()).hexdigest()
        self.origin_password = password
        self.encrypt_password = hashed_password
        return hashed_password

    def sha_384_encrypt(self, password):
        """
        使用sha_384方法加密 \n

        :param password:传入密码 \n
        :return:返回加密后的文本 \n
        """
        hashed_password = hashlib.sha384(password.encode()).hexdigest()
        self.origin_password = password
        self.encrypt_password = hashed_password
        return hashed_password


# 12、AES对称加密解密类
class Encryption_Decryption_Management:
    def __init__(self, password='zl2081515429'):
        """
        AES对称加密解密类 \n

        :param password:传入密钥，建议固定 \n
        """
        self.password = password.encode()
        self.backend = default_backend()

    def _derive_key(self, salt):
        kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100000, backend=self.backend)
        key = kdf.derive(self.password)
        return key

    # 加密
    def encrypt_password(self, password):
        """
        对称加密 \n

        :param password: 需要加密的密码文本 \n
        :return: 返回加密后的密码文本 \n
        """
        salt = os.urandom(16)
        key = self._derive_key(salt)

        padder = padding.PKCS7(128).padder()
        padded_data = padder.update(password.encode()) + padder.finalize()

        iv = os.urandom(16)
        cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=self.backend)
        encryptor = cipher.encryptor()
        ct = encryptor.update(padded_data) + encryptor.finalize()

        all_data = salt + iv + ct
        # print(all_data)
        hex_data = binascii.hexlify(all_data)
        hex_data = hex_data.decode('utf-8')
        return hex_data

    # 解密
    def decrypt_password(self, encrypted_password):
        """
        对称解密 \n

        :param encrypted_password: 需要解密的密码文本 \n
        :return: 已经解密后的密码文本 \n
        """
        encrypted_password = binascii.unhexlify(encrypted_password)

        salt = encrypted_password[:16]
        iv = encrypted_password[16:32]
        ct = encrypted_password[32:]

        key = self._derive_key(salt)

        cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=self.backend)
        decryptor = cipher.decryptor()
        padded_data = decryptor.update(ct) + decryptor.finalize()

        unpadder = padding.PKCS7(128).unpadder()
        password = unpadder.update(padded_data) + unpadder.finalize()

        return password.decode()
